#ifndef _CLASSIFIER_H
#define _CLASSIFIER_H

#include <vector>
#include <string>
#include <iostream>
#include <fstream>

#include "svm_kernel_classifier.h"

using namespace std;

class classifier {

   vector <string> prod;
   vector <int> iprod;

   bool st, term; // st: LHS is start symbol; term: RHS have only terminals

   vector <int> indPos, indNeg;
   vector <int> indNeg1, indNeg2;
   
   svm_kernel_classifier skc;
   bool nr, nr_designated;

   bool aux; // auxiliary production (always matches when RHS is present)

   public:

   classifier (const vector <string> &p, bool s, bool t);
   classifier (const vector <string> &p, bool t);
   void addNeg(posNeg &n);
   void addNeg1(posNeg &n);
   void addNeg2(posNeg &n);
   void addPos(posNeg &p);

   bool degenerate(double &d) const;

   double giveP(int ind) const;
   double giveP(int ind, pn &tsw) const;
   double giveDec(int ind) const;
   double giveDec(int ind, pn &tsw) const;

   bool ifNr() const {
      return nr;
   }
   bool ifNrd() const {
      return nr_designated;
   }

   void setNrd() {
      nr_designated=true;
   }

   void train();
   double accuracy();

   bool relation() const {
      return !st && !term;
   }

   int posSize() const {
      return indPos.size();
   }
   int negSize() const {
      return indNeg.size();
   }

   string giveLhs() const {
      return prod[0];
   }
   int giveiLhs() const {
      return iprod[0];
   }

   bool ifAux() const {
      return aux;
   }

   bool equalsLhs(const string &s) const {
      return s==prod[0];
   }
   bool equalsLhs(int s) const {
      return s==iprod[0];
   }

   bool equalsRhs(const vector <string> &s) const {
      if (s.size() != prod.size()-1) return false;
      for (int i=1; i<prod.size(); ++i) {
	 if (s[i-1] != prod[i]) return false;
      }
      return true;
   }
   bool equalsRhs(const vector <int> &s) const {
      if (s.size() != iprod.size()-1) return false;
      for (int i=1; i<iprod.size(); ++i) {
	 if (s[i-1] != iprod[i]) return false;
      }
      return true;
   }

   void testEg() const;

   bool isTerm() const {
      return term;
   }

   vector <string> giveProd() const {
      return prod;
   }

   vector <int> giveIprod() const {
      return iprod;
   }

   void sampleNegatives();

   vector <string> giveRhs() const {
      vector <string> r;
      for (int i=1; i<prod.size(); ++i) r.push_back(prod[i]);
      return r;
   }
   vector <int> giveiRhs() const {
      vector <int> r;
      for (int i=1; i<iprod.size(); ++i) r.push_back(iprod[i]);
      return r;
   }

   ostream& write(ostream &out) const;
   ostream& writeProd(ostream &out) const {
      out<<prod[0]<<" -> ";
      for (int i=1; i<prod.size(); ++i) out<<prod[i]<<" ";
      out<<"\n";
   }

};

inline ostream& operator << (ostream &out, const classifier &c) {
   return c.write(out);
}

#endif
